package com.gitee.huanminabc.test;

import cn.hutool.core.util.URLUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

/**
 * https://opendata.baidu.com/api.php?t=1727062131671&query=2025%E5%B9%B41%E6%9C%88&format=json&resource_id=39043&tn=wisetpl
 * @author visy.wang
 * @description: 日历数据查询工具
 * @date 2023/1/29 15:55
 */
public class CalendarUtil {
    private static final String URL_V1 = "https://opendata.baidu.com/api.php";
    private static final String URL_V2 = "https://opendata.baidu.com/data/inner";
    private static final String JSONP_CALLBACK_NAME = "jsonp_callback";
    private static final Logger logger = LoggerFactory.getLogger(CalendarUtil.class);

    /**
     * 查询日历（V1）
     * 注意：返回结果的oDate采用的时区是0时区
     * @param year 年，如：2023
     * @param month 月，如：2
     * @param isJSONP 是否返回JSONP（默认返回JSON）
     * @return 返回当前月，上一个月以及下一个月的日历数据
     */
    public static JSONArray queryCalendarV1(int year, int month, boolean isJSONP){
        //拼接参数
        String url = URL_V1 + "?" + getQueryStrV1(year, month, isJSONP);
        return queryCalendar(url, isJSONP, json -> {
            //仅当状态=0时调用成功
            if(!"0".equals(json.getStr("status"))){
                logger.info("接口调用失败");
                return null;
            }
            //提取黄历数据
            return json.getByPath("data[0].almanac", JSONArray.class);
        });
    }

    /**
     * 查询日历（V2）
     * 注意：返回结果的oDate采用的时区是0时区
     * @param year 年，如：2023
     * @param month 月，如：2
     * @param isJSONP 是否返回JSONP（默认返回JSON）
     * @return 返回当前月，上一个月以及下一个月的日历数据
     */
    public static JSONArray queryCalendarV2(int year, int month, boolean isJSONP){
        //拼接参数
        String url = URL_V2 + "?" + getQueryStrV2(year, month, isJSONP);
        return queryCalendar(url, isJSONP, json -> {
            Integer resultCode = json.getInt("ResultCode");
            //仅当结果码=0时调用成功
            if(!Integer.valueOf(0).equals(resultCode)){
                logger.info("接口调用失败");
                return null;
            }
            //提取黄历数据
            return json.getByPath("Result[0].DisplayData.resultData.tplData.data.almanac", JSONArray.class);
        });
    }

    private static JSONArray queryCalendar(String url, boolean isJSONP, Function<JSONObject, JSONArray> parser){
        //拼接参数
        logger.info("完整请求地址: {}", url);
        //发起调用
        String response = HttpUtil.get(url);
        logger.info("原始响应结果: {}", response);
        //提取JSON
        String jsonBody;
        if(isJSONP){
            //返回结果为JSONP时，去除多余字符，提取JSON部分
            int start = response.indexOf("{"), end = response.lastIndexOf("}")+1;
            jsonBody = response.substring(start, end);
        }else{
            jsonBody = response;
        }
        logger.info("JSON响应体: {}", jsonBody);
        //解析返回结果
        return parser.apply(JSONUtil.parseObj(jsonBody));
    }

    private static String getQueryStrV1(int year, int month, boolean isJSONP){
        Map<String,Object> params = new HashMap<>();
        params.put("tn", "wisetpl");
        params.put("format", "json");
        params.put("resource_id", "39043");
        params.put("t", System.currentTimeMillis());
        params.put("query", year+"年"+month+"月");
        if(isJSONP){
            //不加这个参数返回结果为JSON，加了返回的是JSONP
            params.put("cb", JSONP_CALLBACK_NAME);
        }
        return toQueryStr(params);
    }

    private static String getQueryStrV2(int year, int month, boolean isJSONP){
        Map<String,Object> params = new HashMap<>();
        params.put("tn", "reserved_all_res_tn");
        params.put("type", "json");
        params.put("resource_id", "52109");
        params.put("apiType", "yearMonthData");
        params.put("query", year+"年"+month+"月");
        if(isJSONP){
            //不加这个参数返回结果为JSON，加了返回的是JSONP
            params.put("cb", JSONP_CALLBACK_NAME);
        }
        return toQueryStr(params);
    }

    private static String toQueryStr(Map<String,Object> params){
        List<String> kvList = new ArrayList<>();
        params.forEach((k, v) -> {
            kvList.add(k + "=" + v);
        });
        return URLUtil.encode(String.join("&", kvList), StandardCharsets.UTF_8);
    }
}
